import _thread
import subprocess
import time
import tkinter as tk
import tkinter.font as font
from tkinter.messagebox import askyesno
from PIL import Image, ImageTk
import configparser
from tkinter import filedialog, ttk
import pathlib


class Windows:
    def __init__(self, title: str, size: str, is_top: bool = False,
                 is_resizable: bool = False, alpha: int = 1, is_head: bool = False,
                 is_root: bool = False):
        self.config = configparser.ConfigParser()
        self.config_path = "conf.ini"
        self.config.read(self.config_path, encoding="gbk")
        self.parent = None

        if is_root:
            self.win = tk.Tk()
        else:
            self.win = tk.Toplevel()
        self.tk_image = None
        self.button = None
        self.screen_width = int(self.win.winfo_screenwidth())
        self.screen_height = int(self.win.winfo_screenheight())
        self.win.title(title)

        self.win_width = int(size.split("x")[0])
        self.win_height = int(size.split("x")[1])
        _default = "+{0}+{1}".format(int((self.screen_width - self.win_width) / 2),
                                     int((self.screen_height - self.win_height) / 2))
        self.win.geometry(size + _default)
        if is_top:
            self.win.wm_attributes("-topmost", 1)
        if is_resizable:
            self.win.resizable(0, 0)
        if not is_head:
            self.win.overrideredirect(1)
        self.win.wm_attributes("-alpha", alpha)

    def run(self):
        self.win.mainloop()

    def background(self, img_path, text="Desktop Script Developer Tool", font=("华文行楷", 20)):
        self.tk_image = ImageTk.PhotoImage(file=img_path)
        background_label = tk.Label(self.win,
                                    image=self.tk_image,
                                    compound=tk.CENTER,
                                    text=text,
                                    font=font)
        background_label.pack()

    def hide(self):
        self.win.wm_attributes("-alpha", 0)

    def destroy(self):
        self.win.destroy()

    def update(self):
        self.win.update()

    def load_image(self, image_path):
        self.tk_image = ImageTk.PhotoImage(file=image_path)
        return self.tk_image

    def get_option(self, section, option):
        return self.config.get(section, option)

    def get_options(self, section):
        return self.config.options(section)

    def set_option(self, section, option, value):
        self.config.set(section, option, value)  # 修改db_port的值为69
        self.config.write(open(self.config_path, "w"))


class RootWindows(Windows):

    def run(self):
        _thread.start_new_thread(load_tool, (self, ))
        self.win.mainloop()

    def hide(self):
        if bool(self.get_option("root", "debug")):
            self.win.wm_attributes("-alpha", 0)
            return
        for i in map(lambda x: x/100, reversed(range(101))):
            time.sleep(0.01)
            self.win.wm_attributes("-alpha", i)


class HelpWindows(Windows):

    def __init__(self, title: str, size: str, is_top: bool = False,
                 is_resizable: bool = False, alpha: int = 1, is_head: bool = False,
                 is_root: bool = False):

        super().__init__(
            title, size, is_top, is_resizable, alpha, is_head, is_root)
        self.win.protocol("WM_DELETE_WINDOW", self.close_window)
        self.help_images = [(self.get_option("help_images", i).split(" ")[0],
                             self.get_option("help_images", i).split(" ")[1])
                            for i in self.get_options("help_images")]
        self.image_index = int(self.get_option("help", "image_index"))

    def help_button(self, root):
        self.parent = root
        if self.image_index == len(self.help_images):
            self.set_option("help", "image_index", str(self.image_index))
            self.destroy()
            return
        self.tk_image = root.load_image(self.help_images[self.image_index][0])
        self.button = tk.Button(self.win, width=self.win_width, height=self.win_height,
                                command=self.next_help, image=self.tk_image)
        self.win.title(self.help_images[self.image_index][1])
        self.button.pack()

    def next_help(self):
        self.image_index = self.image_index + 1
        if self.image_index == len(self.help_images):
            self.set_option("help", "image_index", str(self.image_index))
            self.destroy()
            return
        self.tk_image = self.parent.load_image(self.help_images[self.image_index][0])
        self.button.config(image=self.tk_image)
        self.win.title(self.help_images[self.image_index][1])
        self.button.update()

    def close_window(self):
        ans = askyesno(message='你要跳过使用手册吗?')
        if ans:
            self.set_option("help", "image_index", str(self.image_index))
            self.destroy()

    def destroy(self):
        self.win.destroy()
        DSFT(title="DSFT", size="600x510", alpha=1, is_head=True, is_resizable=True).run(self.parent)


class DSFT(Windows):
    def __init__(self, title: str, size: str, is_top: bool = False,
                 is_resizable: bool = False, alpha: int = 1, is_head: bool = False,
                 is_root: bool = False):
        super().__init__(
            title, size, is_top, is_resizable, alpha, is_head, is_root)
        self.tree = None
        self.tree_frame = None
        self.log_frame = None
        self.input_frame = None
        self.sc = None
        self.log_entry = None
        self.log_text = None
        self.log_input_text = tk.StringVar("")
        self.project = self.get_option("DSFT", "project")
        self.conf = self.get_option("DSFT", "conf")
        self.is_project = False

    def set_log(self):
        ft = font.Font(family="微软雅黑", size="12")
        self.log_frame = tk.Frame(self.win)
        self.log_entry = tk.Entry(self.log_frame, font=ft,
                                 cursor="cross", textvariable=self.log_input_text)

        self.log_text = tk.Text(self.log_frame, height=11, font=ft)
        self.log_text.pack(side=tk.TOP, expand=tk.YES, fill=tk.BOTH)
        self.log_entry.pack(side=tk.BOTTOM, expand=tk.YES, fill=tk.BOTH)

        self.log_entry.bind('<Return>', self.cmd)

        self.log_frame.grid(row=1, column=0, columnspan=2, sticky=tk.N+tk.E+tk.W)

    def set_input(self):
        self.input_frame = tk.Frame(self.win)
        # self.log_text = tk.Text(self.input_frame, bg="red", height=18)
        # self.log_text.pack()
        self.input_frame.grid(row=0, column=1, sticky=tk.N+tk.W)

    def insert_log(self, message, tag):
        self.log_text.tag_config('out', foreground="black")
        self.log_text.tag_config('err', foreground="red")

        self.log_text.insert("end", message, tag)
        self.log_text.see("end")

    def cmd(self, event):
        cmd_text = str(self.log_input_text.get())
        p = subprocess.Popen(cmd_text, stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                             bufsize=1, universal_newlines=True, shell=True)
        self.log_input_text.set("")
        stdout = p.stdout
        stderr = p.stderr
        path = pathlib.Path().cwd()
        head = f"{str(path)}> {cmd_text}"
        self.log_text.insert("end", head)
        for line in stdout:
            if line is not None and line != "":
                self.insert_log(line, "out")
        for line in stderr:
            if line is not None and line != "":
                self.insert_log(line, "err")
        return "break"

    def set_file_tree(self):
        if self.project is None or self.project == "":
            return
        if self.tree is not None:
            self.tree.destroy()
        self.project = pathlib.Path(self.project)
        self.tree_frame = tk.Frame(self.win)
        self.tree_frame.grid(row=0, column=0, sticky=tk.W)

        self.tree = ttk.Treeview(self.tree_frame)
        self.tree.pack(side=tk.LEFT, fill=tk.Y)
        root = self.tree.insert("", 'end', text=str(self.project.name),
                                open=True, values=(str(self.project)))
        # 加载子目录
        self.load_tree(root, str(self.project))
        # 添加滚动条
        self.sc = tk.Scrollbar(self.tree_frame)
        self.sc.pack(side=tk.RIGHT, fill=tk.Y)
        self.sc.config(command=self.tree.yview)
        # 绑定事件
        self.tree.bind("<<TreeviewSelect>>", self.func)

    def set_menus(self):
        menus = tk.Menu(self.win)
        self.win['menu'] = menus

        menu_set = tk.Menu(menus)
        menus_help = tk.Menu(menus)

        menu_set.add_command(label="新项目", command=self.new_project)
        menu_set.add_command(label="打开项目", command=self.open_project)
        menu_set.add_command(label="设置")
        menu_set.add_command(label="保存")

        menus_help.add_command(label="联系我")
        menus_help.add_command(label="指南")

        menus.add_cascade(label="项目", menu=menu_set)
        menus.add_cascade(label="帮助", menu=menus_help)
        menus.add_cascade(label="关于")

    def func(self, event):
        for i in event.widget.selection():
            print(self.tree.item(i)['text'])

    def load_tree(self, parent, parent_path):
        root = pathlib.Path(parent_path)
        for i in root.iterdir():
            if "dsft.ini" in str(i):
                self.tree.insert(parent, 'end', text=str(i.name) + "  *", values=str(i))
                self.is_project = True
                continue
            second_tree = self.tree.insert(parent, 'end', text=str(i.name), values=str(i))
            # 判断是否是目录
            if i.is_dir():
                self.load_tree(second_tree, str(i))

    def new_project(self):
        self.project = filedialog.askdirectory()
        self.set_option("DSFT", "project", self.project)
        self.conf = str(pathlib.Path(self.project).joinpath("conf.dsft.ini"))
        self.set_option("DSFT", "conf", self.conf)
        with open(self.conf, 'w') as f:
            f.write("[init]")
            f.close()

    def open_project(self):
        path = filedialog.askopenfile(filetypes=[('dsft.ini', 'dsft.ini')])
        if path is None:
            return
        self.project = path
        self.conf = str(pathlib.Path(self.project.name))
        self.project = str(pathlib.Path(self.project.name).parent)
        self.set_option("DSFT", "conf", self.conf)
        self.set_option("DSFT", "project", self.project)
        self.set_file_tree()
        self.tree.update()

    def run(self, parent):
        self.set_menus()
        self.set_file_tree()
        self.set_log()
        self.set_input()
        self.parent = parent
        self.parent.update()


def load_tool(root):
    root.hide()
    help_window = HelpWindows(title="help", size="600x500", alpha=0.9, is_head=True, is_resizable=True)
    help_window.help_button(root)


if __name__ == '__main__':
    win_root = RootWindows(title="win_root", size="500x400", alpha=0.9, is_root=True)
    win_root.background(win_root.get_option("root", "background"))
    win_root.run()
